package com.shanshan.wheel.rpc.common.proxy;

import com.shanshan.wheel.rpc.common.exception.RpcErrorMessage;
import com.shanshan.wheel.rpc.common.exception.RpcException;
import com.shanshan.wheel.rpc.common.provider.RpcServiceProperties;
import com.shanshan.wheel.rpc.common.remoting.constant.RpcResponseCode;
import com.shanshan.wheel.rpc.common.remoting.dto.RpcRequest;
import com.shanshan.wheel.rpc.common.remoting.dto.RpcResponse;
import com.shanshan.wheel.rpc.common.remoting.transport.clent.NettyClient;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.UUID;

/**
 * @Description
 * @ClassName RpcClientProxy
 * @Author 山山大魔王
 * @Date 2022/9/5 22:32
 * @Version 1.0
 */
@Slf4j
public class RpcClientProxy implements InvocationHandler {

    private final NettyClient nettyClient;

    private final RpcServiceProperties rpcServiceProperties;

    public RpcClientProxy(NettyClient nettyClient, RpcServiceProperties rpcServiceProperties) {
        this.nettyClient = nettyClient;

        if(rpcServiceProperties.getGroup() == null){
            rpcServiceProperties.setGroup("");
        }
        if(rpcServiceProperties.getVersion() == null){
            rpcServiceProperties.setVersion("");
        }
        this.rpcServiceProperties = rpcServiceProperties;
    }

    /**
     * 获取代理对象
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T getProxy(Class<T> clazz){
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        RpcRequest rpcRequest = RpcRequest.builder()
                .methodName(method.getName())
                .parameters(args)
                .interfaceName(method.getDeclaringClass().getName())
                .paramTypes(method.getParameterTypes())
                .requestId(UUID.randomUUID().toString())
                .group(rpcServiceProperties.getGroup())
                .version(rpcServiceProperties.getVersion())
                .build();
        // 通过netty客户端调用远程的服务
        RpcResponse<Object> rpcResponse = nettyClient.sendRpcRequest(rpcRequest).get();
        // 检查合法性
        check(rpcRequest,rpcResponse);
        return rpcResponse.getData();
    }

    /**
     * 合法性检查
     * @param rpcRequest
     * @param rpcResponse
     */
    private void check(RpcRequest rpcRequest, RpcResponse<Object> rpcResponse) {
        if(rpcResponse == null){ // 服务调用失败client出问题
            throw new RpcException(RpcErrorMessage.SERVICE_INVOCATION_FAILURE, "client interfaceName:" + rpcRequest.getInterfaceName());
        }
        if(!rpcRequest.getRequestId().equals(rpcRequest.getRequestId())){
            throw new RpcException(RpcErrorMessage.REQUEST_NOT_MATCH_RESPONSE, "interfaceName:" + rpcRequest.getInterfaceName());
        }
        if(rpcResponse.getCode() == null || !RpcResponseCode.SUCCESS.getCode().equals(rpcResponse.getCode())){
            // 服务调用失败server出问题
            throw new RpcException(RpcErrorMessage.SERVICE_INVOCATION_FAILURE, "server interfaceName:" + rpcRequest.getInterfaceName());
        }



    }
}
